//============================================================================
// Name        : test_crash.cpp
// Author      : lidanger
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>

#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <execinfo.h>
#include <string.h>
#include <string>
#include <sys/stat.h>
#include <stdlib.h>

const int MAX_STACK_FRAMES = 128;

void sig_crash(int sig) {
	struct stat buf;
	stat("./crash.log", &buf);

	// 超过10兆则清空内容
	FILE* fd;
	if (buf.st_size > 10 * 1000 * 1000) {
		fd = fopen("./crash.log", "w");
	} else {
		fd = fopen("./crash.log", "at");
	}

	if (NULL == fd) {
		exit(0);
	}

	try {
		char szLine[512] = { 0 };
		time_t t = time(NULL);
		tm* now = localtime(&t);
		sprintf(szLine,
				"#########################################################\n"
						"[%04d-%02d-%02d %02d:%02d:%02d][crash signal number:%d]\n",
				now->tm_year + 1900, now->tm_mon + 1, now->tm_mday,
				now->tm_hour, now->tm_min, now->tm_sec, sig);
		fwrite(szLine, 1, strlen(szLine), fd);

		// 设回默认
		signal(sig, SIG_DFL);

		// 获取堆栈
		void* array[MAX_STACK_FRAMES];
		auto size = backtrace(array, MAX_STACK_FRAMES);
		auto strings = backtrace_symbols(array, size);

		char cmd[128] = { 0, };
		char buff[1024] = { 0 };
		for (auto i = 0; i < size; ++i) {
			sprintf(szLine, "%d %s\n", i, strings[i]);
			fwrite(szLine, 1, strlen(szLine), fd);

			// 获取堆栈信息中的偏移.类似 ./test_crash() [0x8048d88]
			std::string symbol(strings[i]);
			size_t pos1 = symbol.find_first_of("[");
			size_t pos2 = symbol.find_last_of("]");
			std::string address = symbol.substr(pos1 + 1, pos2 - pos1 - 1);

			// 获取代码位置
			sprintf(cmd, "addr2line -e test_crash %s", address.c_str());
			FILE *fPipe = popen(cmd, "r");
			if (fPipe != NULL) {
				char* ret = fgets(buff, sizeof(buff), fPipe);
				pclose(fPipe);
				fwrite(ret, 1, strlen(ret), fd);
			}
		}

		free(strings);
	} catch (...) {
		//
	}

	fflush(fd);
	fclose(fd);
	fd = NULL;
	exit(0);
}

int main() {
	signal(SIGSEGV, sig_crash);
	signal(SIGABRT, sig_crash);

	int* a = NULL;
	a[10] = 0; // crash2
	return 0;
}
